TypeScript 50.6%
JavaScript 46.1%
SQL 2.1%
Shell 0.6%
CSS 0.5%
1import { NextRequest, NextResponse } from "next/server";2import { z } from "zod";3import { assertSameOrigin, requireUser } from "@/lib/auth/session";4import { requestViewing } from "@/lib/inquiries/service";5import { hit } from "@/lib/auth/ratelimit";6import { apiError, handle, parseBody } from "@/lib/api";7export const dynamic = "force-dynamic";8const Body = z.object({ slots: z.array(z.string().datetime({ offset: true })).min(1).max(3), note: z.string().trim().max(500).optional() });9export async function POST(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {10 try { await assertSameOrigin(); const u = await requireUser(); const { id } = await params; const b = await parseBody(req, Body);11 if (b.slots.some((s) => Date.parse(s) < Date.now() - 3600000)) return apiError(400, "invalid_slot", "Les créneaux doivent être à venir");12 const rl = await hit(`view:${u.id}`, 10, 86400); if (!rl.ok) return apiError(429, "rate_limited", "Trop de demandes de visite aujourd'hui.");13 const v = await requestViewing(id, u.id, b.slots, b.note); return NextResponse.json({ ok: true, viewingId: v.id }, { status: 201 }); } catch (e) { return handle(e); }14}15